package org.lep.leetcode.datastructure.linkedlist.linkedlistcycle;

/**
 * Source : https://oj.leetcode.com/problems/linked-list-cycle-ii/
 *
 * Created by lverpeng on 2017/9/14.
 *
 * Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
 *
 * Follow up:
 * Can you solve it without using extra space?
 */
public class LinkedListCycle2 {

    /**
     * 如果链表是循环的，则找到循环的开始节点
     * 否则，返回null
     *
     * 依然使用双指针法，如果是循环链表的话，
     * slow和fast第一次相遇之后，将slow = head，
     * 然后将slow和fast每次移动一个节点，第二次相遇的时候就是循环的起始节点
     *
     * 原理：
     * 假设head到start的距离a，slow和fast第一次相遇的位置距离start为b，相遇点距离start为c，第一次相遇的时候fast走过的长度一定是slow的两倍
     * (a + b) * 2 = a + b + c + b
     * 那么a = c
     * 也就是说，现在让两个指针slow指向head，fast指向第一次相遇的位置，然后每次两个指针移动一个节点，直到下一次相遇，正好相遇在start位置
     *
     * @param head
     * @return
     */
    public LinkedNode findCycleStart (LinkedNode head) {
        if (head == null) {
            return null;
        }
        LinkedNode slow = head;
        LinkedNode fast = head;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                break;
            }
        }
        if (fast == slow) {
            // 链表存在循环
            slow = head;
            while (slow != fast) {
                slow = slow.next;
                fast = fast.next;
            }
            return slow;
        }
        return null;
    }

    private class LinkedNode {
        int value;
        LinkedNode next;

    }

    /**
     * 创建普通的链表
     * @param arr
     * @return
     */
    public LinkedNode createList (int[] arr) {
        if (arr.length == 0) {
            return null;
        }
        LinkedNode head = new LinkedNode();
        head.value = arr[0];
        LinkedNode pointer = head;
        for (int i = 1; i < arr.length; i++) {
            LinkedNode node = new LinkedNode();
            node.value = arr[i];
            pointer.next = node;
            pointer = pointer.next;
        }
        return head;
    }

    /**
     * 将链表变为循环链表，循环起始为第index个node
     * @param head
     * @param index
     */
    public void makeCycle (LinkedNode head, int index) {
        if (head == null) {
            return;
        }
        LinkedNode tail = head;
        int count = 1;
        while (tail.next != null) {
            tail = tail.next;
            count++;
        }
        LinkedNode p = head;
        if (index > count) {
            index = index % count;
        } else if (index < 0) {
            index = Math.abs(index);
        }
        while (p != null) {
            index--;
            if (index < 1) {
                tail.next = p;
                break;
            }
            p = p.next;
        }

    }

    public static void main(String[] args) {
        LinkedListCycle2 linkedListCycle = new LinkedListCycle2();
        LinkedNode list = linkedListCycle.createList(new int[]{1,2,3,4,5});

        System.out.println(linkedListCycle.findCycleStart(list) + " == null");

        linkedListCycle.makeCycle(list, 2);
        System.out.println(linkedListCycle.findCycleStart(list).value + " == 2");
    }
}
